/*
 *  icmp.c
 *  xcode
 *
 *  Created by Emiel Goor,van on 25-01-08.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */


#include "eth.h"
#include "pack.h"
#include "ip.h"
#include "icmp.h"
#include "ne2k.h"

#define ICMP_ECHO_REPLY 0
#define ICMP_ECHO_REQUEST 8
#define ICMP_TTL_EXPIRED 11

// ids and sequences
int icmpLastId = 0;
int icmpLastSeq = 0;

int icmpWait = 0;

// wait system (AGAIN)

void Ping( unsigned int ip, int count, int timeout )
{
	// tell user
	printf( "Pinging %d.%d.%d.%d with 26 bytes of data\n", IPAddr0( ip ), IPAddr1( ip ), IPAddr2( ip ), IPAddr3( ip ) );
	
	// main loop
	int i;
	for( i = 0; i < count; i++ )
	{
		
		// icmp header to work with
		icmpHeader_t* icmp;
		
		// length of data
		int len = sizeof( icmpHeader_t ) + 26; // 26 letters in alphabet
		
		// get the card
		struct ne2000_t* myCard = (struct ne2000_t*) getNeCard( 0 );
		
		// data to work with
		char* data = (char*) kmalloc( len );
		
		// create a packet
		packet_t* packet = packetCreate( data, len );
		
		// set the header
		icmp = ( icmpHeader_t* ) packet->data;
		
		// do it
		icmp->type = ICMP_ECHO_REQUEST;
		icmp->code = 0;
		icmp->checksum = 0;
		icmp->id = icmpLastId++;
		icmp->seq = icmpLastSeq++;
		
		// fill the rest
		memcpy( packet->data + sizeof( icmpHeader_t ), "abcdefghijklmnopqrstuvwxyz", 26 );
		
		// checksum it
		icmp->checksum = packetChecksum( packet, len );

		// send it
		if( ipSendPacket( myCard->eth, ip, packet, IP_TYPE_ICMP, 1 ) == 0 )
		{
			printf( "Destination host unreachable.\n" );
			continue;
		}
	
		// wait for the reply
		icmpWait = 1;

		while( icmpWait )
		{
	//		printf("|");
		}
		
		if( icmpWait )
			continue;
		
		// get the time
		int start =0;
		int end = 2;
		
		// received
		printf( "Reply from %d.%d.%d.%d: time=%dms\n", IPAddr0( ip ), IPAddr1( ip ), IPAddr2( ip ), IPAddr3( ip ), end - start );
	}
}

static void handleEchoRequest(ethernet_t *eth, packet_t *p)
{
	packet_t *cp;
	icmpHeader_t *icmp;
	ipHeader_t *ip;
	char *data;
	int icmpLen;

	icmp = (icmpHeader_t *)ipStripHeader(p);
	ip = (ipHeader_t *)ethernetStripHeader(p);

	icmpLen = ntohs(ip->len) - sizeof(ipHeader_t);
	data = (char*) kmalloc(icmpLen);
	memcpy(data, icmp, icmpLen);
	cp = packetCreate(data, icmpLen);

	icmp = (icmpHeader_t *) cp->data;

	// echo reply, compute the checksum
	icmp->type = ICMP_ECHO_REPLY;
	icmp->checksum = 0;
	icmp->checksum = packetChecksum(cp, /*sizeof(icmpHeader_t)*/ cp->len);

	// send the packet
	ipSendPacket( eth, ip->ipSrc, cp, IP_TYPE_ICMP, 1 );
}

void handleIcmpPacket(ethernet_t *eth, packet_t *p)
{
	icmpHeader_t *icmpPkt = (icmpHeader_t *)ipStripHeader(p);
	
	if(icmpPkt->type == ICMP_ECHO_REQUEST)
		handleEchoRequest(eth, p);
	else if( icmpPkt->type == ICMP_ECHO_REPLY )
		icmpWait = 0;
	else
		printf( "Unhandled ICMP packet (type is %d, code is %d)\n", icmpPkt->type, icmpPkt->code );
}
